<?php
	
	/**
	 * Pk Core class file.
	 * 
	 * @author Brian Bal <brian@youbeqb.com>
	 * @version 1.0
	 * @package MVC
	 */
	
	/**
	 * PkCore class
	 *
	 * @package pink-koala
	 * @author Brian Bal
	 **/
	
	Class PkCore
	{
		public $controller;
		private $controller_name;
		private $action_name;
		private $args;
		private $layout;
		private $plugins;
		private $routes;
		
		function __construct($plugins = null, $routes = null)
		{
			if($plugins == null){ $this->plugins == array(); }
			if($routes == null){ $this->routes == array(); }
			
			// connect to the database
			$pk_database = PkDatabase::getPkDatabase();
			$pk_database->connectToDatabase(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
			
			$this->plugins = array();
			$this->initPlugins($plugins);
			$this->routes = $routes;
			
			$this->runHooks("preSystem");
			
			$router = new PkRouter();
			$the_route = $router->route($_SERVER['REQUEST_URI'], $this->routes);
			
			$controller_name = $the_route['controller'];
			$action_name = $the_route['action'];
			
			$this->router($controller_name, $action_name);
			$this->delegate();
		}
		
		private function router($controller_name, $action_name)
		{
			// Run preController Hooks:
			$this->runHooks("preController");
			
			// format the names properly
			$controller_name = str_replace( "_" , " " , $controller_name );
			$controller_name = ucwords(strtolower($controller_name));
			$controller_name = str_replace( " " , "_" , $controller_name );
			$action_name = strtolower($action_name);
			
			// Check if the controller is available
			// Initiatilze the class
			$class_name = $controller_name . 'Controller';
			
			if( file_exists(getFilePath($class_name)) )
			{
				$this->controller = new $class_name();
				$this->controller_name = strtolower($controller_name);
			}
			else
			{
				$this->notFound('no-controller');
			}
			
			
			// Check if the action is available
			if (is_callable(array($this->controller, $action_name)) == false)
			{
				$this->notFound("no-action $action_name");
			}else{
				$this->action_name = $action_name;
			}
			
			$this->controller->controller_name = $this->controller_name;
			$this->controller->action_name = $this->action_name;
			$this->controller->view_name = $this->action_name;
		}
		
		private function delegate()
		{
			// Run postControllerConstructor Hooks:
			$this->runHooks("postControllerConstructor");
			
			// Include the Helper Files for the controller
			helper("application");
			helper($this->getControllerName());
			
			// Run action
			$this->controller->{$this->action_name}();
			
			// Run postController Hooks:
			$this->runHooks("postController");
			
			// render the view
			$this->controller->page();
			
			// flush the flash variables
			flush_flash();
			
			// Shutdown the System:
			$this->shutdown();
		}
		
		private function notFound($msg)
		{
			header("HTTP/1.0 404 Not Found");
			include(WEBROOT_DIR . "404.html");
			$this->shutdown();
		}
		
		function initPlugins($plugins)
		{
			foreach($plugins as $plugin)
			{
				$file_name = uncamelize($plugin);
				$file = PROJECT_DIR . "library/plugins/$plugin/init.php";
				if(file_exists($file))
				{
					require($file);
				}
			}
			
			foreach(get_declared_classes() as $class)
			{
				$reflectionClass = new ReflectionClass($class);
				if($reflectionClass->implementsInterface('PkPlugin'))
				{
					$this->plugins[] = $reflectionClass;
				}
			}
		}
		
		private function runHooks($hook_point)
		{
			/****************************************************************
			 *					possible hook point values					*
			 ****************************************************************
			 *																*
			 *	preSystem:													*
			 *		Called very early during system execution. Only the 	*
			 *		benchmark and hooks class have been loaded at this  	*
			 *		point. No routing or other processes have happened.		*
			 *																*
			 *	preController:												*
			 *		Called immediately prior to any of your controllers  	*
			 *		being called. All base classes, routing, and security   *
			 *		checks have been done.									*
			 *																*
			 *	postControllerConstructor: 								*
			 *		Called immediately after your controller is 			*
			 *		instantiated, but prior to any method calls happening.  *
			 *																*
			 *	postController: 											*
			 *		Called immediately after your controller is fully 		*
			 *		executed.												*	
			 *																*
			 *	postSystem: 												*
			 *		Called after the final rendered page is sent to the 	*
			 *		browser, at the end of system execution after the 		*
			 *		finalized data is sent to the browser.					*
			 *																*
			 ****************************************************************/
			
			foreach($this->plugins as $plugin)
			{
				if($plugin->hasMethod($hook_point))
				{
					$reflectionMethod = $plugin->getMethod($hook_point);
					
					if($reflectionMethod->isStatic())
					{
						$reflectionMethod->invoke(null, $this);
					}else{
						// not static so need an instance
						$pluginInstance = $plugin->newInstance();
						$reflectionMethod->invokeArgs($pluginInstance, array($this));
					}
				}
			}
			
		}
		
		public function shutdown()
		{
			// close database connection
			PkDatabase::closeDatabaseConnection();
			
			// Run postSystem Hooks:
			$this->runHooks("postSystem");
			exit();
		}
		
		public function log($log, $data, $header = false)
		{
			$go = true;
			if(isset($this->controller->log))
			{
				if($this->controller->log === false)
				{
					$go = false;
				}
			}
			
			if(isset($this->view->log))
			{
				if($this->view->log === false)
				{
					$go = false;
				}
			}
			
			if($go)
			{
				if(file_exists(LOG_DIR . "$log.log") == false)
				{
					if(is_writable(LOG_DIR))
					{
						$log_file = fopen(LOG_DIR . "$log.log", 'a');
						
						if($header !== false)
						{
							fwrite($log_file, $header . "\n");
						}
						
						fwrite($log_file, $data);
						fclose($log_file);
					}
				}else{
					if(is_writable(LOG_DIR . "$log.log"))
					{
						$log_file = fopen(LOG_DIR . "$log.log", 'a');
						fwrite($log_file, $data);
						fclose($log_file);
					}
				}
				
			}
		}
		
		// this function may not be needed anymore
		public function getControllerName()
		{
			return $this->controller_name;
		}
		
		// this function may not be needed anymore
		public function getActionName()
		{
			return $this->action_name;
		}
	}
	